/*
 * File:   linux.c
 * Author: otavio
 *
 * Created on May 5, 2011, 7:22 PM
 */

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include "indices.h"
#include "others.h"

char * sharedMem;
sem_t *mutex, *board_mutex, *hl, *ms;

void board() {
    //ToDo entrar no barco (posicionar no array)
    sharedMem[NUM_BOARDED_INDEX]++;

    int index = (int) sharedMem[NUM_BOARDED_INDEX] + (int) SEAT_0_INDEX - 1;
    sharedMem[index] = MS_CHAR;

    // printf("\nboard() NUM_BOARDED: %d\n", sharedMem[NUM_BOARDED_INDEX]);
}

void rowBoat() {

    sharedMem[NUM_BOARDED_INDEX] = 0;

    int i;

    for (i = 0; i < 4; i++) {
        int seatIndex = SEAT_0_INDEX + i;
        if (sharedMem[seatIndex] == MS_CHAR)
            printf(" MS ");
        else if (sharedMem[seatIndex] == HL_CHAR)
            printf(" HL ");
        else printf("E%d", seatIndex);
    }
    printf("\n");

    for (i = 0; i < 4; i++) {

        int seatIndex = SEAT_0_INDEX + i;
        sharedMem[seatIndex] = '\0';
    }
}

void getOnBoard() {
    sem_wait(board_mutex);
    board();
    if (sharedMem[NUM_BOARDED_INDEX] == 4) {

        rowBoat();
    }
    sem_post(board_mutex);
}

void employee() {
    // printf("\nTentando pegar MUTEX\n");
    sem_wait(mutex);
    // printf("\nConseguiu pegar MUTEX\n");
    sharedMem[NUM_MICROSOFT_INDEX]++;
    if (sharedMem[NUM_MICROSOFT_INDEX] == 4) {
        sem_post(ms);
        sem_post(ms);
        sem_post(ms);
        sharedMem[NUM_MICROSOFT_INDEX] -= 4;
        sem_post(mutex);
        getOnBoard();
    } else if (sharedMem[NUM_HACKERS_INDEX] >= 2 && sharedMem[NUM_MICROSOFT_INDEX] >= 2) {
        sem_post(ms);
        sem_post(hl);
        sem_post(hl);
        sharedMem[NUM_HACKERS_INDEX] -= 2;
        sharedMem[NUM_MICROSOFT_INDEX] -= 2;
        sem_post(mutex);
        getOnBoard();
    } else {

        sem_post(mutex);
        sem_wait(ms);
        getOnBoard();
    }
}

void setSemaphores() {

    if ((mutex = sem_open(MUTEX_SEM, O_CREAT, S_IRWXU | S_IRWXO, 1)) == SEM_FAILED) {
        fprintf(stderr, "Mutex could not be opened!\n");
    }
    if ((board_mutex = sem_open(BOARD_MUTEX_SEM, O_CREAT, S_IRWXU | S_IRWXO, 1)) == SEM_FAILED) {
        fprintf(stderr, "Board mutex could not be opened!\n");
    }
    if ((hl = sem_open(HL_SEM, O_CREAT, S_IRWXU | S_IRWXO, 0)) == SEM_FAILED) {
        fprintf(stderr, "HL sem could not be opened!\n");
    }
    if ((ms = sem_open(MS_SEM, O_CREAT, S_IRWXU | S_IRWXO, 0)) == SEM_FAILED) {

        fprintf(stderr, "MS sem could not be opened!\n");
    }
}

void setSharedMemory() {

    int shMemSegID;

    int shmFlags = IPC_CREAT | SHM_PERM;

    if ((shMemSegID = shmget(SHM_KEY, 7 * sizeof (char), shmFlags)) < 0) {
        perror("SERVER: shmget");
        exit(EXIT_FAILURE);
    }

    shmFlags = 0;
    if ((sharedMem = shmat(shMemSegID, NULL, shmFlags)) == (void *) - 1) {

        perror("SERVER: shmat");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char** argv) {
    setSemaphores();
    setSharedMemory();
    employee();
    return (EXIT_SUCCESS);
}
